const express = require('express');
const path = require('path');
const fs = require('fs');
const chalk = require("chalk");
const UUID = require('uuid');
const { count } = require('console');

const db = require(path.join(__dirname, './../middleware/mysql/db'));
const fileutil = require(path.join(__dirname, './../middleware/file/fileutil'));
const dateutil = require(path.join(__dirname, './../middleware/date/dateutil'));
var dataresult = require(path.join(__dirname, './../module/dataresult'));
const plugservice = require(path.join(__dirname, './../service/plugservice'))
const menuservice = require(path.join(__dirname, './../service/menuservice'))
const plugm = require(path.join(__dirname, './../module/plug'));
const funcm = require(path.join(__dirname, './../module/func'));
const plugpath_bak = path.join(__dirname, "./../webapp/plugins_bak");
const plugpath = path.join(__dirname, "./../webapp/plugins");

const plugprojectname = "project.conf.js";

const output = "";
const output_icon = "static";
const icon_class = {vl:'class:',lg:'6'};
const icon_img = {vl:'img:',lg:'4'};

/**从压缩包中读取配置文件 */
function getZipProjectConf(filename){
    return new Promise(async function(resolve,reject){
        try{
            let projectPlugPath = path.join(plugpath_bak, filename);
            let projectPlugName = path.join(output, plugprojectname);
            let projectPlug = await fileutil.readZipPorjectConf(projectPlugPath, projectPlugName);
            resolve(projectPlug);
        }catch(err){
            console.log(err);
            reject(err);
        }
    })
}
/**
 * 校验上传的插件（判断新增还是升级）
 * */
function check(params) {
    return new Promise(async function (resolve, reject) {
        try {
            /**参数列表中必须有filename */
            if (!params.filename) {
                resolve("要校验的文件路径不正确，请检查:" + params.filename);
            }
            //1、将项目配置文件解析为对象
            let projectPlug = await getZipProjectConf(params.filename);
            let pluguuid = projectPlug.uuid;
            if (!pluguuid) {
                dataresult.state = 3;
                dataresult.msg = "上传的插件项目配置中没有uuid，请检查:";
                resolve(dataresult);
            }

            /**校验插件中图片是否正确 */
            let isicon = judgeIcon(projectPlug,params.filename);
            if (!isicon) {
                dataresult.state = 3;
                dataresult.msg = "插件或功能的图标文件路径错误，请检查";
                resolve(dataresult);
                return this;
            }

            let mysqlPlugMsg = [];
            let sql = "select * from plug where id = '" + pluguuid + "'";
            await db.query(sql, function (err, rows) {
                if (err) {
                    console.log(chalk.red("[hotdog sql] 查询插件报错" + sql));
                    reject("查询插件报错")
                }
                mysqlPlugMsg = rows;
            });
            //2、判断本次上传为新增插件还是修改插件，封装信息返回
            if (mysqlPlugMsg.length == 0 || typeof (pluguuid) == "undefined") {
                //判断插件名称是否已经存在
                if (await checkPlug(projectPlug.name)) {
                    dataresult.state = 3;
                    dataresult.msg = "新建插件时发现插件的名称已经存在，请检查上传插件的配置文件！";
                } else {
                    dataresult.state = 0;
                    dataresult.msg = "项目中未找到该插件，确认新建插件吗？";
                    dataresult.data = await newFuncList(projectPlug);
                }
                resolve(dataresult);
            } else {
                //判断插件名称是否已经改变
                if (await checkPlug(projectPlug.name, projectPlug.uuid)) {
                    dataresult.state = 3;
                    dataresult.msg = "升级插件时发现插件名称有变化，请检查上传插件的配置文件！";
                } else {
                    dataresult.state = 1;
                    dataresult.msg = "项目中已存在该插件，确认对插件中的功能做相应操作吗？";
                    dataresult.data = await updateFuncList(projectPlug);
                }
                
                 resolve(dataresult);
            }
        } catch (err) {
            //6、返回校验失败信息
            console.log(chalk.red("[hotdog checkplug] 校验插件出现异常"));
            console.log(err);
            reject("校验插件出现异常");
        }
    });
}

/**校验插件-校验图标 */
function judgeIcon(projectPlug,filename){

    let rtval = true;

    //判断插件图标
    let plugicon = projectPlug.icon;
    let zippath = path.join(plugpath_bak,filename);
    
    if(!hasIcon(zippath,plugicon)){
        return false;
    }
    //判断功能图标
    let funcarr = projectPlug.func;
    funcarr.forEach((func)=>{
        let funcicon = func.icon;
        
        if(!hasIcon(zippath,funcicon)){
            rtval = false;
            return false
        }
    });
    return rtval;
}

/**判断压缩包中图标是否存在 */
function hasIcon(zippath,iconpath){
        if(!iconpath){
            return false;
        }
         /**是否需要判断 -- 如果'img:'开头则需要判断 */
		let isjudge = (iconpath.indexOf(icon_img.vl)=='0')
		if(isjudge){
            iconpath = iconpath.substr(icon_img.lg, iconpath.length);
            let iconFullPath = path.join(output_icon, iconpath);
			let hasIcon = fileutil.readZipFile(zippath,iconFullPath);
            if(!hasIcon){
                return false;
            }
		}else if(!(iconpath.indexOf(icon_class.vl)=='0')){
			return false;
		}
        return true;
}

/**判断插件为更新或新增 */
function judgeUporIn(pluguuid){
    return new Promise(async function (resolve, reject) {
        let sql = "select * from plug where id = '" + pluguuid + "'";
           await db.query(sql, function (err, rows) {
                if (err) {
                    console.log(chalk.red("[hotdog sql] 查询插件报错" + sql));
                    reject(err)
                }
                if(rows.length==0 || typeof(rows)=="undefined"){
                    resolve("0");
                }else{
                    resolve("1");
                }
            });
    });
}

/**
 * 校验插件名称是否存在（新增插件和更新插件都在此判断）
 *  */
function checkPlug(plugname, plugid) {
    return new Promise(async function (resolve, reject) {
        try {
            let judge = 'new';
            let sql = "select count(0) sums from plug where name='" + plugname + "'";
            
            if (plugid) {
                sql = sql + " and id='" + plugid + "'";
                judge = 'update';
            }
            await db.query(sql, function (err, rows) {
                let sums = rows[0].sums;
                //新增插件时判断名称已存在
                if (sums > 0 && judge=='new') {
                    resolve(true)
                }
                //跟新插件时判断插件名称已变化（假定id相同为同一插件）
                else if (sums==0 && judge=='update') {
                    resolve(true);
                } else {
                    resolve(false);
                }
            });
        } catch (err) {
            console.log(err);
            reject("checkPlug 检查插件时报错");
        }
    });
}


/**
 * 新增插件提示列表
 */
function newFuncList(projectPlug) {

    let projectFunc = projectPlug.func;
    Array.from(projectFunc, (func) => {
        func["opt"] = "add";
    })
    return projectFunc;
}

/**
 * 升级插件提示列表 
 * */
function updateFuncList(projectPlug) {
    let results = new Array();
    let projectFunc = projectPlug.func;

    let mysqlfunc = [];
    let sql = "select * from func where plugid='" + projectPlug.uuid + "'";
    return new Promise(async function (resolve, reject) {

        mysqlfunc = await selectFuncByPluguuid(sql);
        /**准备参数 */
        let funcChangeMsg = new Array();
        var arrayProj = JSON.parse(JSON.stringify(projectFunc)).slice(0);
        var arrayDb = JSON.parse(JSON.stringify(mysqlfunc)).slice(0);

        /**
         * 功能url相同则视为同一功能 , url前后加塑杠进行比较防止特殊情况
         * */
        Array.from(arrayProj, (func) => {
            func.url = "|" + func.url + "|";
        });
        Array.from(arrayDb, (func) => {
            func.url = "|" + func.url + "|";
        });
        let projectUrl = JSON.stringify(arrayProj);
        let mysqlUrl = JSON.stringify(arrayDb);

        /**查找新增和修改的功能 */
        for (let func of projectFunc) {
            let urlstr = "|" + func.url + "|";
            if (mysqlUrl.includes(urlstr)) {
                func["opt"] = "update";
                funcChangeMsg.push(func);
            } else {
                func["opt"] = "add";
                funcChangeMsg.push(func);
            }
        }
        /**查找要删除的功能 */
        for (let func of mysqlfunc) {
            let urlstr = "|" + func.url + "|";
            if (!projectUrl.includes(urlstr)) {
                func["opt"] = "del";
                funcChangeMsg.push(func);
            }
        }
        results = funcChangeMsg;
        resolve(results);
    });
}

/**
 * 根据插件id查找功能列表 
 * */
function selectFuncByPluguuid(sql) {
    return new Promise((resolve, reject) => {
        try {
            db.query(sql, function (err, rows) {
                err ? reject(err) : resolve(rows)
            });
        } catch (err) {
            console.log(err);
            reject(err);
        }
    })
}

/**
 * 安装插件
 * @param params 存放filename 
 */
function install(params) {
    return new Promise(async function (resolve, reject) {
        try {
            let state = params.state;
            let filename = params.filename;

            //安装插件
            if (state=='0') {
                newPlug(filename);
                dataresult.succExec();
            }
            //升级插件
            else if(state=='1'){
                uploadPlug(filename);
                dataresult.succExec();
            }else{
                dataresult.errorExec();
            }
            /**清空菜单缓存 */
            menuservice.cleanMunuCatch();
            resolve(dataresult);
        } catch (err) {
            console.log(err);
            reject("安装插件时后台抛出异常");
        }
    });
}

/**
 * 卸载插件
 */
function uninstall(plugid) {
    return new Promise(async function (resolve, reject) {
        try {

            /**查询plug */
            let searchplug = { id: plugid }
            let plugrsdata = await plugservice.queryPlug(searchplug);
            let plugzhdata = JSON.parse(JSON.stringify(plugrsdata));
            let plugdata = plugzhdata.data[0];

            //删除插件文件
            let newfile = path.join(plugpath, plugdata.name);
            await fileutil.delFloder(newfile);

            //删除插件数据库信息
            let sqls = new Array();
            let delmenu = "delete from menu where plugid = '" + plugid + "'";
            let delfunc = "delete from func where plugid = '" + plugid + "'";
            let delplug = "delete from plug where id = '" + plugid + "'";

            sqls.push(delmenu);
            sqls.push(delfunc);
            sqls.push(delplug);

            //处理mysql事务
            await db.excSqlsTranscation(sqls);
            /**清空菜单缓存 */
            menuservice.cleanMunuCatch();
            dataresult.succExec();
            resolve(dataresult);
        } catch (err) {
            console.log(chalk.red("[hotdog uninstall] 卸载插件出现异常"));
            console.log(err);
            reject("卸载插件后台抛出异常");
        }
    });
}



/**
 * 安装插件-新建插件
 * @param {插件解压路径} filename 
 */
function newPlug(filename) {
    return new Promise(async function (resolve, reject) {
        try {
            //解压文件
            let projectPlug = await unzipplug(filename);

            //插入数据库
            await installDatabase(projectPlug);
        } catch (err) {
            console.log(err);
            reject(err);
        }
    });
}
/**安装数据库信息*/
function installDatabase(projectPlug) {
    new Promise(async function (resolve, reject) {
        try {
            // insert func by for
            let projectFunc = projectPlug.func;
            let sqls = new Array();
            for (let func of projectFunc) {
                func["id"] = UUID.v1();
                func["plugid"] = projectPlug.uuid;
                let sql = await db.getInsert(func, funcm.colum, funcm.tablename);
                sqls.push(sql);
            }
            // insert plug once
            projectPlug["id"] = projectPlug.uuid;
            projectPlug["fixdate"] = dateutil.getDate();
            let sql = db.getInsert(projectPlug, plugm.colum, plugm.tablename);
            sqls.push(sql);

            //处理mysql事务
            await db.excSqlsTranscation(sqls);
            resolve();
        } catch (err) {
            reject(err);
        }
    });

}

/**解压插件到plugins */
function unzipplug(filename){
    return new Promise(async function (resolve, reject) {
        try{
            //获取配置文件
            let zippath = path.join(plugpath_bak, filename);
            let projectPlug = await getZipProjectConf(filename);
            let plugRealPath = path.join(plugpath, projectPlug.name);
            //解压文件
            await fileutil.unzipFile(zippath,plugRealPath);
            resolve(projectPlug);
        }catch(err){
            console.log(err);
            reject(err);
        }
    });
}

/**
 * 安装插件-升级插件
 * @param {插件解压路径} filename 
 */
function uploadPlug(filename) {
    return new Promise(async function (resolve, reject) {
        try {
            //解压文件
            let projectPlug = await unzipplug(filename);

            //更新数据库
            await uploadDatabase(projectPlug);
        } catch (err) {
            console.log(err);
            reject("升级插件时后台抛出异常");
        }
    });
}

/**
 * 插件升级更新数据库
 */
function uploadDatabase(projectPlug) {
    return new Promise(async function (resolve, reject) {
        try {
            /**升级数据库信息*/
            let funcmsg = await updateFuncList(projectPlug);
            let sqls = new Array();
            funcmsg.forEach(async function (func) {
                //新增功能
                if (func.opt == 'add') {
                    func["id"] = UUID.v1();
                    func["plugid"] = projectPlug.uuid;
                    // func['url'] = projectplug.name + "/"+func.url;
                    let sql = await db.getInsert(func, funcm.colum, funcm.tablename);
                    sqls.push(sql);
                }
                //修改功能
                else if (func.opt == 'update') {
                    let whereparm = [{ key: "url", value: func.url },{ key: "plugid", value: projectPlug.uuid }];
                    let sql = await db.getUpdate(func, funcm.colum, funcm.tablename, whereparm);
                    sqls.push(sql);
                }
                //删除功能
                else if (func.opt == 'del') {
                    if (func.id == "" || typeof (func.id) == "undefined") {
                        console.log(chalk.red("删除的信息错误，没有功能主键"));
                        reject("error");
                    }
                    //删除菜单
                    let sql = "delete from menu where plugid = '" + func.plugid + "' and funcid='" + func.id + "'";
                    sqls.push(sql);
                    //删除功能
                    sql = "delete from func where plugid = '" + func.plugid + "' and url='" + func.url + "'";
                    sqls.push(sql);
                }
            });
            //处理mysql事务
            await db.excSqlsTranscation(sqls);
            resolve();
        } catch (err) {
            console.log(err);
            reject(err);
        }
    });
}

/**
 * 安装文件
 * @param {旧文件} oldfile 
 * @param {新文件} newfile 
 */
function installFile(oldfile, newfile) {
    return new Promise(async function (resolve, reject) {
        try {
            //删除原有文件
            await fileutil.delFloder(newfile);

            //新建根目录
            await fs.mkdirSync(newfile, function (err) {
                if (err) {
                    console.error(err);
                    reject(err);
                }
            });

            //复制文件
            await fileutil.copyFloder(oldfile, newfile);
            resolve("succ");
        } catch (err) {
            console.log(err);
            reject(err);
        }
    });
}

/**校验插件 */
exports.check = check;
/**新增插件 */
exports.install = install;
/**卸载插件 */
exports.uninstall = uninstall;
/**判断更新或新增(0新增，1更新) */
exports.judgeUporIn=judgeUporIn;
/**复制文件 参数：(oldfile,newfile) */
exports.installFile=installFile;
/**插入数据库信息 */
exports.installDatabase=installDatabase;
/**更新数据库信息 */
exports.uploadDatabase=uploadDatabase;